1 Introduction

The National Football League (NFL) is a syndicate of 32 teams which over the last several decades has become not only America’s favorite past time but also one of the most profitable leagues globally. In 2023, the league generated over 20 billion dollars in revenue and held 93 spots in the top 100 most watched broadcasts. A large part of the success the league enjoys is due to its scarcity. The regular season is only 18 weeks long, where each team plays 17 games along with one bye week for rest. This is in sharp contrast to other sports leagues where teams might play hundreds of games.

Although the NFL season is short, there is an abundance of data generated each game and over the span of a season. Finding ways to leverage this data is important to the success and health of a team and its players. More recently, fantasy leagues and the growing popularity of sports gambling have amplified the significance of this data for fans and Wall Street investors seeking profitable opportunities.

For this project, we selected a relatively simple data set encompassing box score statistics for each NFL team during the 2023 regular season gathered from pro-football-reference (https://www.pro-football-reference.com/). Our data consists of 544 observations and 25 features (23 predictors and 2 response) which are listed below. Our goal is simple:

  1. Can we use box score statistics to predict the points scored by a team via linear regression?
  2. Can we use box score statistics to predict the result of the game via logistic regression?

Team : Name of the team
Week : Week of the season
Day : Day the game was played
Date : Date the game was played
Time : Time the game was played
Result : W if the won or L if they lost
OT : If the game went into overtime
Rec : Win-loss record
isHome : Weather the team played at home or away
Opp : Opponent the team played against
Tm_score : Points scored
Opp_score : Points scored by opponent
1stD_Off : First downs gained by offense
TotYd_Off : Total yardage gained by offense
PassY_Off : Passing yardage gained by offense
RushY_Off : Rushing yardage gained by offense
TO_Off : Turnovers by the offense
1stD_Def : First downs given up by defense
TotY_Def : Total yardage given up by defense
PassY_Def : Passing yardage given up by defense
RushY_Def : Rushing yardage given up by defense
TO_Def : Turnovers caused by defense
OffenseExp : Expected points by offense
DefenseExp : Expected points by defense
SpTms_Exp : Expected points by special teams

Note: The expected points features are calculated via play by play data. According to pro-football-reference, expected points represent the estimated point value at the start of a given play, based on down, distance, and field position.

2 EDA and Feature Engineering

2.1 Cleaning Data and Feature Engineering

A quick glance at our data, shows us that almost all of our columns have missing values. We handle this in two ways:

  1. The 32 missing values in many of our columns occur because this data includes the bye where no data is generated. We drop these rows.
  2. The other missing values are due to the way our source inputs the data, leaving things blank when an event does not occur. For example, in the OT column, if the game goes into overtime, OT is listed, otherwise, the cell is left blank. Similarly, if a team does not generate a turnover, the entry is blank. We fill these missing values in as zero.
     Team                Week          Day                Date          
 Length:576         Min.   : 1.0   Length:576         Length:576        
 Class :character   1st Qu.: 5.0   Class :character   Class :character  
 Mode  :character   Median : 9.5   Mode  :character   Mode  :character  
                    Mean   : 9.5                                        
                    3rd Qu.:14.0                                        
                    Max.   :18.0                                        
                                                                        
     Time             boxscore            Result               OT           
 Length:576         Length:576         Length:576         Length:576        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
     Rec               atHome              Opp               Tm_score    
 Length:576         Length:576         Length:576         Min.   : 0.00  
 Class :character   Class :character   Class :character   1st Qu.:16.00  
 Mode  :character   Mode  :character   Mode  :character   Median :21.00  
                                                          Mean   :21.77  
                                                          3rd Qu.:28.00  
                                                          Max.   :70.00  
                                                          NA's   :32     
   Opp_score       X1stD_Off       TotYd_Off       PassY_Off    
 Min.   : 0.00   Min.   : 6.00   Min.   : 58.0   Min.   : -9.0  
 1st Qu.:16.00   1st Qu.:16.00   1st Qu.:273.0   1st Qu.:167.8  
 Median :21.00   Median :19.00   Median :335.0   Median :215.0  
 Mean   :21.77   Mean   :19.26   Mean   :331.6   Mean   :218.9  
 3rd Qu.:28.00   3rd Qu.:23.00   3rd Qu.:389.0   3rd Qu.:268.0  
 Max.   :70.00   Max.   :33.00   Max.   :726.0   Max.   :472.0  
 NA's   :32      NA's   :32      NA's   :32      NA's   :32     
   RushY_Off         TO_Off        X1stD_Def        TotY_Def    
 Min.   : 17.0   Min.   :1.000   Min.   : 6.00   Min.   : 58.0  
 1st Qu.: 77.0   1st Qu.:1.000   1st Qu.:16.00   1st Qu.:273.0  
 Median :107.0   Median :2.000   Median :19.00   Median :335.0  
 Mean   :112.7   Mean   :1.877   Mean   :19.26   Mean   :331.6  
 3rd Qu.:141.0   3rd Qu.:2.000   3rd Qu.:23.00   3rd Qu.:389.0  
 Max.   :350.0   Max.   :6.000   Max.   :33.00   Max.   :726.0  
 NA's   :32      NA's   :185     NA's   :32      NA's   :32     
   PassY_Def       RushY_Def         TO_Def        OffenseExp     
 Min.   : -9.0   Min.   : 17.0   Min.   :1.000   Min.   :-35.860  
 1st Qu.:167.8   1st Qu.: 77.0   1st Qu.:1.000   1st Qu.: -6.798  
 Median :215.0   Median :107.0   Median :2.000   Median :  1.990  
 Mean   :218.9   Mean   :112.7   Mean   :1.877   Mean   :  1.628  
 3rd Qu.:268.0   3rd Qu.:141.0   3rd Qu.:2.000   3rd Qu.:  9.895  
 Max.   :472.0   Max.   :350.0   Max.   :6.000   Max.   : 48.650  
 NA's   :32      NA's   :32      NA's   :185     NA's   :32       
   DefenseExp        SpTms_Exp      
 Min.   :-48.650   Min.   :-12.380  
 1st Qu.: -9.895   1st Qu.: -2.845  
 Median : -1.990   Median :  0.000  
 Mean   : -1.628   Mean   :  0.000  
 3rd Qu.:  6.798   3rd Qu.:  2.845  
 Max.   : 35.860   Max.   : 12.380  
 NA's   :32        NA's   :32       

To clean our data, we set our binary variables to be either 1 or 0. We also create, two new binary variables.

  1. We use the Time column to create a new variable called isPrimeTime which lets us know whether or not the game was played at night on national television.
  2. A isThursday feature is created from the Day column which lets us know if the game was played on Thursday. Thursday night games are played on a short week which can lead to sloppy play and increased risk of injury.

After dropping unnecessary columns and renaming other columns, we are left with the following features: OT,atHome, Tm_score , Opp_score, 1stD_Off, TotYd_Off, PassY_Off, RushY_Off, TO_Off, 1stD_Def, TotY_Def, PassY_Def, RushY_Def, TO_Def, OffenseExp, DefenseExp, SpTms_Exp, isPrimeTime, and isThursday.

2.2 Visualising Distributions

The distribution for our continuous numerical variables for offense and defense are shown below. The first down rate, total yardage, and passing yards look to be normally distributed. The rushing yards have a slight skew but nothing major catches the eye. Turnovers on the other hand have a noticeable right skew which is to be expected.

Comparing the defensive plots vs the offensive plots shows that the distributions are exactly the same but this is to be expected. Since two teams play in a game, we have observations for both teams from the same game. For example, suppose the Eagles play the Giants and gain 400 total yards. This will show up as 400 under TotYd_Off but will show up again in another observation of the Giants as TotY_Def. We see in the two plots below that the offensive stats do not correlate with the defensive stats for each observation.

It should be expected that passing and rushing yards are correlated with total yards which is indeed the case. Surprisingly, there is little correlation between rush and pass yards.

To further capture relationships between our numerical variables we create a Pearson correlation plot. We see that offensive expected points feature is highly correlated with yardage. The same applies for defensive expected points and yardage given up. And of course the total yardage is dependent on rushing and passing yardage.

2.3 Relationship to response variables

We would now like to take a closer look at the relationship between our features and the response variables.To capture this relationship, we create a scatter plot for each numerical variable against our response variable. For our categorical variables, we create density plots.

Observations:

  1. Defensive statistics have no bearing on the points scored which is not too surprising since defenses rarely score points.
  2. Special teams expected points has no correlation with points scored. This is a bit surprising since, field goals and extra points are a significant chunk of points scored during a normal game.
  3. Turnovers may have a slight correlation.
  4. A difference in the distribution between games that went into overtime vs those that did not. Similarly, home vs away games have a slight difference in distributions.

Plotting our features against our second response variable, we see that almost all features have a difference in there distribtions for a win vs a loss. The two turnover features look a bit odd and they may pose problems downstream.

3 Linear Regression

Points are primarily scored by the offense and a small amount by the special teams via extra points, field goals, punt and kick returns. In rare cases, points can be scored by the defense. For this to happen, a turnover is required. This fact helps us choose \(|.3|\) as the cutoff for selecting features from the correlation plot. This decision is also supported by our scatter plots.

3.1 Model One

The first model we build is a naive model to set a baseline. From our visualization, we know that offensive expected points was the highest correlated feature to our response variable so we choose this instead of other offensives stats. Let \(O=\)OT,\(H\)=atHome, \(P\)=Tm_score , \(F_O\)=1stD_Off, \(Y_O\) = TotYd_Off, \(P_O\) = PassY_Off, \(R_O\) =RushY_Off, \(TO_O\) =TO_Off, \(F_D\) =1stD_Def, \(T_D\) =TotY_Def, \(P_D\) =PassY_Def, \(R_D\) = RushY_Def, \(TO_D\) =TO_Def, \(E_O\) =OffenseExp, \(E_D\) = DefenseExp, \(E_S\)SpTms_Exp, \(N\) = isPrimeTime, and \(T\) = isThursday.

Our first model: \[M1: \text{Points} = \alpha_0 + \alpha_1E_D+ \alpha_2E_O + \alpha_3E_S + \alpha_4F_O + \alpha_5 H + \alpha_6 TO_O + \alpha_7 TO_D + \alpha_8 O + \alpha_9 T + \alpha_{10} N + \epsilon\]

Summarized statistics of the regression coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 13.3393576 1.2557828 10.622345 0.0000000
SpTms_Exp 0.4601147 0.0584145 7.876726 0.0000000
OffenseExp 0.7110176 0.0300953 23.625539 0.0000000
DefenseExp 0.1865435 0.0215198 8.668459 0.0000000
X1stD_Off 0.1696519 0.0662606 2.560374 0.0107304
TO_Off 1.3859644 0.2171200 6.383402 0.0000000
TO_Def 1.6217397 0.2063290 7.859970 0.0000000
atHome1 0.1725996 0.4206915 0.410276 0.6817683
OT1 4.1180071 0.9824969 4.191369 0.0000325
isThursday1 4.2122865 0.9246353 4.555619 0.0000065
isPrimeTime1 -1.5391315 0.5751517 -2.676044 0.0076789

From the output of our first model, we see that playing at home had a small effect on the outcome. Furthermore, we know from our correlation plots, that the defensive and special teams had little relationship to our response variable. Our second model is focused on offensive stats and we remove the atHOME variable.

3.2 Model 2

Our second model: \[M2: \text{Points} = \alpha_0 + \alpha_1E_O + \alpha_2F_O + \alpha_3 TO_D + \alpha_4 TO_O + \alpha_5 O + \alpha_6 T + \alpha_7 N + \epsilon\]

Summarized statistics of the regression coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 13.2627618 1.3295888 9.975085 0.0000000
OffenseExp 0.6353635 0.0314334 20.212975 0.0000000
X1stD_Off 0.1325279 0.0713863 1.856490 0.0639322
TO_Off 0.9979134 0.2306389 4.326735 0.0000181
TO_Def 2.5389342 0.1947000 13.040237 0.0000000
isThursday1 4.0789361 1.0026368 4.068209 0.0000545
OT1 4.0403746 1.0652762 3.792795 0.0001659
isPrimeTime1 -1.5557811 0.6239310 -2.493515 0.0129489

3.3 Model Three

The next two models we build, we replace offensive expected points by the three yardage statistics. The third model uses TotYd_Off and fourth model will use RushY_Off + PassY_Off.

\[M3: \text{Points} = \alpha_0 + \alpha_1Y_O + \alpha_2F_O + \alpha_3 TO_D + \alpha_4 TO_O + \alpha_5 O + \alpha_6 T + \alpha_7 N + \alpha_8 H + \epsilon\]

3.4 Model Four

In our fourth model, we use both rush and passing yards instead of total yards. \[M4: \text{Points} = \alpha_0 + \alpha_1R_O + \alpha_1P_O + \alpha_3F_O + \alpha_4 TO_D + \alpha_5 TO_O + \alpha_6 O + \alpha_7 T + \alpha_8 N + \alpha_9 H + \epsilon\]

The respective \(R^2\) values for our four models are:

  1. naiveModel = 0.772688,
  2. offModel = 0.7309864,
  3. yardModel = 0.6181533,
  4. typeYardage_model = 0.6183322

Our models based on expected value features perform much better than the ones using yardage. This may be because the expected value features are based on other information and thus are more informative.

4 Logistic regression

For our logistic models, we will omit the three expected points features because they capture the margin of points between two teams. The first model we build includes all features aside from expected points since our exploration showed a difference in distribution for each feature.

4.1 Model One

In our fourth model, we use both rush and passing yards instead of total yards. \[M1: \text{win} = \alpha_0 + \alpha_1P + \alpha_3F_O + \alpha_4 F_D + \alpha_5 TO_D + \alpha_6 TO_O + \alpha_7 Y_O + \alpha_8 Y_D + \alpha_9 O + \alpha_{10} T + \alpha_{11} N + \alpha_{12} H + \epsilon\]

Summary of the significant tests of the logistic regression model
Estimate Std. Error z value Pr(>|z|)
(Intercept) 3.0183789 1.1132013 2.7114402 0.0066992
Tm_score 0.2588536 0.0337682 7.6656022 0.0000000
X1stD_Off -0.1537508 0.0556692 -2.7618654 0.0057472
TotYd_Off 0.0094882 0.0033489 2.8332499 0.0046077
TO_Off -0.9399173 0.1513878 -6.2086741 0.0000000
X1stD_Def -0.0715834 0.0518345 -1.3809988 0.1672793
TotY_Def -0.0207389 0.0033062 -6.2727850 0.0000000
TO_Def 0.7652793 0.1590230 4.8123814 0.0000015
atHome1 -0.2030294 0.2935336 -0.6916734 0.4891425
isThursday1 -0.3598061 0.6806176 -0.5286464 0.5970507
isPrimeTime1 0.0162286 0.4045573 0.0401145 0.9680019
OT1 -0.7039025 0.5495380 -1.2808988 0.2002292

From the above output, we can see that our binary variables and first downs given up by the defense have little impact and are not significant. So in our second model, we remove them.

4.2 Model Two

\[M1: \text{win} = \alpha_0 + \alpha_1P + \alpha_2F_O + \alpha_3 TO_D + \alpha_4 TO_O + \alpha_5 Y_O + \alpha_6 Y_D + \epsilon\]

Summary of the significant tests of the logistic regression model
Estimate Std. Error z value Pr(>|z|)
(Intercept) 2.3184603 0.9886073 2.345178 0.0190180
Tm_score 0.2397413 0.0311415 7.698446 0.0000000
X1stD_Off -0.1501170 0.0552602 -2.716547 0.0065967
TotYd_Off 0.0101172 0.0032726 3.091486 0.0019916
TO_Off -0.8967764 0.1461624 -6.135480 0.0000000
TotY_Def -0.0233840 0.0026075 -8.968079 0.0000000
TO_Def 0.8302725 0.1545586 5.371894 0.0000001

5 Predictive Modeling

5.1 Linear Regression

We pick our first and third linear regression models to perform predictive modeling. First we split our data \(80:20\) between training and test sets. From there, we perform 5-fold cross validation on our training set and then use our test set to get final results for our chosen model.

Model 1 - Naive
intercept RMSE Rsquared MAE RMSESD RsquaredSD MAESD
TRUE 4.880135 0.7616962 3.809666 0.3319993 0.0162899 0.2574751
Model 2 - Total Yards
intercept RMSE Rsquared MAE RMSESD RsquaredSD MAESD
TRUE 6.386919 0.59905 4.998638 0.4116265 0.0376984 0.3158955

We see that model 1 performs better across all metrics and therefore chose it to be our final model. The final results are:

      RMSE        R2     MAE
1 4.886772 0.7616925 3.85993

5.2 Logistic Regression Cross Validation

We use our training data to perform 5-fold cross validation and then use our test set to get final results for our chosen model.

Model 1 - All Features
parameter Accuracy Kappa AccuracySD KappaSD
none 0.8693051 0.7385168 0.0235174 0.0473083
Model 2 - Some Features
parameter Accuracy Kappa AccuracySD KappaSD
none 0.8715517 0.7430096 0.0409873 0.0822253

Cohen’s kappa and accuracy are high in both models. We see little drop off in the second, simpler model and thus choose it as our final model. We now use our entire training data to fit the model and test it on our test data. A cufusion matrix is provided for the final model, along with various statistics to measure model performance, with accuracy at \(90\)%.

Confusion Matrix and Statistics

          Reference
Prediction  0  1
         0 44  4
         1 13 47
                                        
               Accuracy : 0.8426        
                 95% CI : (0.76, 0.9055)
    No Information Rate : 0.5278        
    P-Value [Acc > NIR] : 5.522e-12     
                                        
                  Kappa : 0.6871        
                                        
 Mcnemar's Test P-Value : 0.05235       
                                        
            Sensitivity : 0.7719        
            Specificity : 0.9216        
         Pos Pred Value : 0.9167        
         Neg Pred Value : 0.7833        
             Prevalence : 0.5278        
         Detection Rate : 0.4074        
   Detection Prevalence : 0.4444        
      Balanced Accuracy : 0.8467        
                                        
       'Positive' Class : 0             
                                        

6 Conclusion

Our models worked fairly well on a limited data set but could use improvement. More data never hurts. Perhaps our models, particularly our linear regression model, would perform better if we had data across multiple years or if we had more features like time of possession, loss of downs, 3rd and 4th down conversions, etc.

One thing not mentioned in the above sections is the Box-Cox transformation. This was attempted for the linear regression but had little effect on performance and occasionally hurt the performance. Therefore, it was left out.

Furthermore, the expected points features were the best performers for linear regression which is less than ideal since they are opaque variables. It is not clear how they are calculated from other statistics by pro-football-reference and it would be better to have the actual statistics instead.

LS0tCnRpdGxlOiAnUmVncmVzc2lvbiBBbmFseXNpcycKYXV0aG9yOiAiIChZb3UgYXJlIGV4cGVjdGVkIHRvIGdpdmUgYSBkZXNjcmlwdGl2ZSB0aXRsZSkiCmRhdGU6ICIgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICB0b2NfZmxvYXQ6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHNtb290aF9zY3JvbGw6IHllcwogICAgdGhlbWU6IGx1bWVuCiAgd29yZF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX21kOiB5ZXMKICBwZGZfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQogICBsaWJyYXJ5KGtuaXRyKQp9CgppZiAoIXJlcXVpcmUoImRwbHlyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQogICBsaWJyYXJ5KGRwbHlyKQp9CgppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKICAgbGlicmFyeShnZ3Bsb3QyKQp9CiAgCmlmICghcmVxdWlyZSgicGF0Y2h3b3JrIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikKICAgbGlicmFyeShwYXRjaHdvcmspCn0KCmlmICghcmVxdWlyZSgicmVzaGFwZTIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIpCiAgIGxpYnJhcnkocmVzaGFwZTIpCn0KCmlmICghcmVxdWlyZSgidGlueXRleCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInRpbnl0ZXgiKQogICBsaWJyYXJ5KHRpbnl0ZXgpCn0KCmlmICghcmVxdWlyZSgiY2FyZXQiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIpCiAgIGxpYnJhcnkoY2FyZXQpCn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPUZBTFNFLCAgICAgICMgc3VwcHJlc3MgY29kZSBjaHVuawogICAgICAgICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSwgICAjIHN1cHByZXNzIHdhcm5pbmdzIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cz1UUlVFLCAgICMgc3VwcHJlc3Mgb3V0cHV0CiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlPUZBTFNFLCAgICMgc3VwcHJlc3MgbWVzc2FnZQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudD1OQSkKCmBgYAoKCiMgSW50cm9kdWN0aW9uCgpUaGUgTmF0aW9uYWwgRm9vdGJhbGwgTGVhZ3VlIChORkwpIGlzIGEgc3luZGljYXRlIG9mIDMyIHRlYW1zIHdoaWNoIG92ZXIgdGhlIGxhc3Qgc2V2ZXJhbCBkZWNhZGVzIGhhcyBiZWNvbWUgbm90IG9ubHkgQW1lcmljYSdzIGZhdm9yaXRlIHBhc3QgdGltZSBidXQgYWxzbyBvbmUgb2YgdGhlIG1vc3QgcHJvZml0YWJsZSBsZWFndWVzIGdsb2JhbGx5LiBJbiAyMDIzLCB0aGUgbGVhZ3VlIGdlbmVyYXRlZCBvdmVyIDIwIGJpbGxpb24gZG9sbGFycyBpbiByZXZlbnVlIGFuZCBoZWxkIDkzIHNwb3RzIGluIHRoZSB0b3AgMTAwIG1vc3Qgd2F0Y2hlZCBicm9hZGNhc3RzLiBBIGxhcmdlIHBhcnQgb2YgdGhlIHN1Y2Nlc3MgdGhlIGxlYWd1ZSBlbmpveXMgaXMgZHVlIHRvIGl0cyBzY2FyY2l0eS4gVGhlIHJlZ3VsYXIgc2Vhc29uIGlzIG9ubHkgMTggd2Vla3MgbG9uZywgd2hlcmUgZWFjaCB0ZWFtIHBsYXlzIDE3IGdhbWVzIGFsb25nIHdpdGggb25lIGJ5ZSB3ZWVrIGZvciByZXN0LiBUaGlzIGlzIGluIHNoYXJwIGNvbnRyYXN0IHRvIG90aGVyIHNwb3J0cyBsZWFndWVzIHdoZXJlIHRlYW1zIG1pZ2h0IHBsYXkgaHVuZHJlZHMgb2YgZ2FtZXMuCgpBbHRob3VnaCB0aGUgTkZMIHNlYXNvbiBpcyBzaG9ydCwgdGhlcmUgaXMgYW4gYWJ1bmRhbmNlIG9mIGRhdGEgZ2VuZXJhdGVkIGVhY2ggZ2FtZSBhbmQgb3ZlciB0aGUgc3BhbiBvZiBhIHNlYXNvbi4gRmluZGluZyB3YXlzIHRvIGxldmVyYWdlIHRoaXMgZGF0YSBpcyBpbXBvcnRhbnQgdG8gdGhlIHN1Y2Nlc3MgYW5kIGhlYWx0aCBvZiBhIHRlYW0gYW5kIGl0cyBwbGF5ZXJzLiBNb3JlIHJlY2VudGx5LCBmYW50YXN5IGxlYWd1ZXMgYW5kIHRoZSBncm93aW5nIHBvcHVsYXJpdHkgb2Ygc3BvcnRzIGdhbWJsaW5nIGhhdmUgYW1wbGlmaWVkIHRoZSBzaWduaWZpY2FuY2Ugb2YgdGhpcyBkYXRhIGZvciBmYW5zIGFuZCBXYWxsIFN0cmVldCBpbnZlc3RvcnMgc2Vla2luZyBwcm9maXRhYmxlIG9wcG9ydHVuaXRpZXMuCgpGb3IgdGhpcyBwcm9qZWN0LCB3ZSBzZWxlY3RlZCBhIHJlbGF0aXZlbHkgc2ltcGxlIGRhdGEgc2V0IGVuY29tcGFzc2luZyBib3ggc2NvcmUgc3RhdGlzdGljcyBmb3IgZWFjaCBORkwgdGVhbSBkdXJpbmcgdGhlIDIwMjMgcmVndWxhciBzZWFzb24gZ2F0aGVyZWQgZnJvbSBwcm8tZm9vdGJhbGwtcmVmZXJlbmNlIChodHRwczovL3d3dy5wcm8tZm9vdGJhbGwtcmVmZXJlbmNlLmNvbS8pLiBPdXIgZGF0YSBjb25zaXN0cyBvZiA1NDQgb2JzZXJ2YXRpb25zIGFuZCAyNSBmZWF0dXJlcyAoMjMgcHJlZGljdG9ycyBhbmQgMiByZXNwb25zZSkgd2hpY2ggYXJlIGxpc3RlZCBiZWxvdy4gT3VyIGdvYWwgaXMgc2ltcGxlOgoKMS4gQ2FuIHdlIHVzZSBib3ggc2NvcmUgc3RhdGlzdGljcyB0byBwcmVkaWN0IHRoZSBwb2ludHMgc2NvcmVkIGJ5IGEgdGVhbSB2aWEgbGluZWFyIHJlZ3Jlc3Npb24/CjIuIENhbiB3ZSB1c2UgYm94IHNjb3JlIHN0YXRpc3RpY3MgdG8gcHJlZGljdCB0aGUgcmVzdWx0IG9mIHRoZSBnYW1lIHZpYSBsb2dpc3RpYyByZWdyZXNzaW9uPwoKYFRlYW1gIDogTmFtZSBvZiB0aGUgdGVhbSBcCmBXZWVrYCA6IFdlZWsgb2YgdGhlIHNlYXNvbiBcCmBEYXlgCSA6IERheSB0aGUgZ2FtZSB3YXMgcGxheWVkIFwKYERhdGVgCSA6IERhdGUgdGhlIGdhbWUgd2FzIHBsYXllZCBcCmBUaW1lYAkgOiBUaW1lIHRoZSBnYW1lIHdhcyBwbGF5ZWQgXApgUmVzdWx0YCA6IFcgaWYgdGhlIHdvbiBvciBMIGlmIHRoZXkgbG9zdAlcCmBPVGAJICAgOiBJZiB0aGUgZ2FtZSB3ZW50IGludG8gb3ZlcnRpbWUgXApgUmVjYAkgICA6IFdpbi1sb3NzIHJlY29yZCBcCmBpc0hvbWVgIDogV2VhdGhlciB0aGUgdGVhbSBwbGF5ZWQgYXQgaG9tZSBvciBhd2F5IFwKYE9wcGAJICAgOiBPcHBvbmVudCB0aGUgdGVhbSBwbGF5ZWQgYWdhaW5zdCBcCmBUbV9zY29yZWAJOiBQb2ludHMgc2NvcmVkIFwKYE9wcF9zY29yZWAJOiBQb2ludHMgc2NvcmVkIGJ5IG9wcG9uZW50IFwKYDFzdERfT2ZmYAk6IEZpcnN0IGRvd25zIGdhaW5lZCBieSBvZmZlbnNlIFwKYFRvdFlkX09mZmAJOiBUb3RhbCB5YXJkYWdlIGdhaW5lZCBieSBvZmZlbnNlIFwKYFBhc3NZX09mZmAJOiBQYXNzaW5nIHlhcmRhZ2UgZ2FpbmVkIGJ5IG9mZmVuc2UgXApgUnVzaFlfT2ZmYAk6IFJ1c2hpbmcgeWFyZGFnZSBnYWluZWQgYnkgb2ZmZW5zZSBcCmBUT19PZmZgCSAgOiBUdXJub3ZlcnMgYnkgdGhlIG9mZmVuc2UgXApgMXN0RF9EZWZgCTogRmlyc3QgZG93bnMgZ2l2ZW4gdXAgYnkgZGVmZW5zZSBcCmBUb3RZX0RlZmAJOiBUb3RhbCB5YXJkYWdlIGdpdmVuIHVwIGJ5IGRlZmVuc2UgXApgUGFzc1lfRGVmYAk6IFBhc3NpbmcgeWFyZGFnZSBnaXZlbiB1cCBieSBkZWZlbnNlIFwKYFJ1c2hZX0RlZmAJOiBSdXNoaW5nIHlhcmRhZ2UgZ2l2ZW4gdXAgYnkgZGVmZW5zZSBcCmBUT19EZWZgCSAgOiBUdXJub3ZlcnMgY2F1c2VkIGJ5IGRlZmVuc2UgXApgT2ZmZW5zZUV4cGAJOiBFeHBlY3RlZCBwb2ludHMgYnkgb2ZmZW5zZSBcCmBEZWZlbnNlRXhwYAk6IEV4cGVjdGVkIHBvaW50cyBieSBkZWZlbnNlIFwKYFNwVG1zX0V4cGAgICA6IEV4cGVjdGVkIHBvaW50cyBieSBzcGVjaWFsIHRlYW1zIFwKIAoqTm90ZToqIFRoZSBleHBlY3RlZCBwb2ludHMgZmVhdHVyZXMgYXJlIGNhbGN1bGF0ZWQgdmlhIHBsYXkgYnkgcGxheSBkYXRhLiBBY2NvcmRpbmcgdG8gcHJvLWZvb3RiYWxsLXJlZmVyZW5jZSwgZXhwZWN0ZWQgcG9pbnRzIHJlcHJlc2VudCB0aGUgZXN0aW1hdGVkIHBvaW50IHZhbHVlIGF0IHRoZSBzdGFydCBvZiBhIGdpdmVuIHBsYXksIGJhc2VkIG9uIGRvd24sIGRpc3RhbmNlLCBhbmQgZmllbGQgcG9zaXRpb24uIAoKIyBFREEgYW5kIEZlYXR1cmUgRW5naW5lZXJpbmcKCiMjIENsZWFuaW5nIERhdGEgYW5kIEZlYXR1cmUgRW5naW5lZXJpbmcKQSBxdWljayBnbGFuY2UgYXQgb3VyIGRhdGEsIHNob3dzIHVzIHRoYXQgYWxtb3N0IGFsbCBvZiBvdXIgY29sdW1ucyBoYXZlIG1pc3NpbmcgdmFsdWVzLiBXZSBoYW5kbGUgdGhpcyBpbiB0d28gd2F5czoKCjEuIFRoZSAzMiBtaXNzaW5nIHZhbHVlcyBpbiBtYW55IG9mIG91ciBjb2x1bW5zIG9jY3VyIGJlY2F1c2UgdGhpcyBkYXRhIGluY2x1ZGVzIHRoZSBieWUgd2hlcmUgbm8gZGF0YSBpcyBnZW5lcmF0ZWQuIFdlIGRyb3AgdGhlc2Ugcm93cy4KMi4gVGhlIG90aGVyIG1pc3NpbmcgdmFsdWVzIGFyZSBkdWUgdG8gdGhlIHdheSBvdXIgc291cmNlIGlucHV0cyB0aGUgZGF0YSwgbGVhdmluZyB0aGluZ3MgYmxhbmsgd2hlbiBhbiBldmVudCBkb2VzIG5vdCBvY2N1ci4gRm9yIGV4YW1wbGUsIGluIHRoZSBPVCBjb2x1bW4sIGlmIHRoZSBnYW1lIGdvZXMgaW50byBvdmVydGltZSwgT1QgaXMgbGlzdGVkLCBvdGhlcndpc2UsIHRoZSBjZWxsIGlzIGxlZnQgYmxhbmsuIFNpbWlsYXJseSwgaWYgYSB0ZWFtIGRvZXMgbm90IGdlbmVyYXRlIGEgdHVybm92ZXIsIHRoZSBlbnRyeSBpcyBibGFuay4gV2UgZmlsbCB0aGVzZSBtaXNzaW5nIHZhbHVlcyBpbiBhcyB6ZXJvLgoKYGBge3J9CmRhdGEgPC0gcmVhZC5jc3YoJy9Vc2Vycy9oc2FsaW0vc3RhNTUxL2RhdGEudHh0JykKc3VtbWFyeShkYXRhKQpgYGAKClRvIGNsZWFuIG91ciBkYXRhLCB3ZSBzZXQgb3VyIGJpbmFyeSB2YXJpYWJsZXMgdG8gYmUgZWl0aGVyIDEgb3IgMC4gV2UgYWxzbyBjcmVhdGUsIHR3byBuZXcgYmluYXJ5IHZhcmlhYmxlcy4KCjEuIFdlIHVzZSB0aGUgYFRpbWVgIGNvbHVtbiB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIGBpc1ByaW1lVGltZWAgd2hpY2ggbGV0cyB1cyBrbm93IHdoZXRoZXIgb3Igbm90IHRoZSBnYW1lIHdhcyBwbGF5ZWQgYXQgbmlnaHQgb24gbmF0aW9uYWwgdGVsZXZpc2lvbi4KMi4gQSBgaXNUaHVyc2RheWAgZmVhdHVyZSBpcyBjcmVhdGVkIGZyb20gdGhlIGBEYXlgIGNvbHVtbiB3aGljaCBsZXRzIHVzIGtub3cgaWYgdGhlIGdhbWUgd2FzIHBsYXllZCBvbiBUaHVyc2RheS4gVGh1cnNkYXkgbmlnaHQgZ2FtZXMgYXJlIHBsYXllZCBvbiBhIHNob3J0IHdlZWsgd2hpY2ggY2FuIGxlYWQgdG8gc2xvcHB5IHBsYXkgYW5kIGluY3JlYXNlZCByaXNrIG9mIGluanVyeS4KCkFmdGVyIGRyb3BwaW5nIHVubmVjZXNzYXJ5IGNvbHVtbnMgYW5kIHJlbmFtaW5nIG90aGVyIGNvbHVtbnMsIHdlIGFyZSBsZWZ0IHdpdGggdGhlIGZvbGxvd2luZyBmZWF0dXJlczogCmBPVGAsYGF0SG9tZWAsIGBUbV9zY29yZWAJLCBgT3BwX3Njb3JlYCwgYDFzdERfT2ZmYCwgYFRvdFlkX09mZmAsIGBQYXNzWV9PZmZgLCBgUnVzaFlfT2ZmYCwgYFRPX09mZmAsIGAxc3REX0RlZmAsIGBUb3RZX0RlZmAsIGBQYXNzWV9EZWZgLCBgUnVzaFlfRGVmYCwgYFRPX0RlZmAsIGBPZmZlbnNlRXhwYCwgYERlZmVuc2VFeHBgLCBgU3BUbXNfRXhwYCwgYGlzUHJpbWVUaW1lYCwgYW5kIGBpc1RodXJzZGF5YC4KCmBgYHtyLCByZXN1bHRzPUZBTFNFfQojIFJlbW92ZSBCeWUgd2VlawpkYXRhID0gZGF0YSAlPiUgZmlsdGVyKE9wcCAhPSAnQnllIFdlZWsnKQoKIyBDaGFuZ2UgTkEgdG8gMCBpbiBUT19EZWYgYW5kIFRPX09mZgpkYXRhW2lzLm5hKGRhdGEpXSA8LSAwCgojIGZpbGwgaW4gT1QKZGF0YSRPVFtkYXRhJE9UPT0iIl0gPC0gIjAiCmRhdGEkT1RbZGF0YSRPVD09Ik9UIl0gPC0gIjEiCgojIGZpbGwgaW4gSG9tZSBTdGF0dXMKZGF0YSRhdEhvbWVbZGF0YSRhdEhvbWU9PSIiXSA8LSAiMSIKZGF0YSRhdEhvbWVbZGF0YSRhdEhvbWU9PSJAIl0gPC0gIjAiCgojVGh1cnNkYXkgZ2FtZXMKZGF0YSRpc1RodXJzZGF5IDwtIHdpdGgoZGF0YSwgaWZlbHNlKERheT09IlRodSIsIDEsIDApKQpkYXRhJGlzVGh1cnNkYXkgPC0gYXMuY2hhcmFjdGVyKGRhdGEkaXNUaHVyc2RheSkKCiNQcmltZSB0aW1lIGdhbWVzCmRhdGEkaXNQcmltZVRpbWUgPC0gd2l0aChkYXRhLCBpZmVsc2UoVGltZT09Ijc6MTVQTSBFVCIgfCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaW1lPT0iODowMFBNIEVUIiB8IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpbWU9PSI4OjE1UE0gRVQiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaW1lPT0iODoyMFBNIEVUIiAsIDEsIDApKQpkYXRhJGlzUHJpbWVUaW1lIDwtIGFzLmNoYXJhY3RlcihkYXRhJGlzUHJpbWVUaW1lKQoKIyBDaGFuZ2UgcmVzdWx0IHRvIDEgb3IgMApkYXRhJHdpbiA8LSB3aXRoKGRhdGEsIGlmZWxzZShSZXN1bHQ9PSdXJywxLDApKQpkYXRhJHdpbiA8LSBhcy5jaGFyYWN0ZXIoZGF0YSR3aW4pCgpkYXRhIDwtIGRhdGEgJT4lIHNlbGVjdCgtYyhUZWFtLCBXZWVrLCBEYXksIERhdGUsIFRpbWUsIGJveHNjb3JlLCBSZXN1bHQsIFJlYywgT3BwX3Njb3JlLCBPcHApKQpoZWFkKGRhdGEpCmBgYAoKIyMgVmlzdWFsaXNpbmcgRGlzdHJpYnV0aW9ucwoKVGhlIGRpc3RyaWJ1dGlvbiBmb3Igb3VyIGNvbnRpbnVvdXMgbnVtZXJpY2FsIHZhcmlhYmxlcyBmb3Igb2ZmZW5zZSBhbmQgZGVmZW5zZSBhcmUgc2hvd24gYmVsb3cuIFRoZSBmaXJzdCBkb3duIHJhdGUsIHRvdGFsIHlhcmRhZ2UsIGFuZCBwYXNzaW5nIHlhcmRzIGxvb2sgdG8gYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIFRoZSBydXNoaW5nIHlhcmRzIGhhdmUgYSBzbGlnaHQgc2tldyBidXQgbm90aGluZyBtYWpvciBjYXRjaGVzIHRoZSBleWUuIFR1cm5vdmVycyBvbiB0aGUgb3RoZXIgaGFuZCBoYXZlIGEgbm90aWNlYWJsZSByaWdodCBza2V3IHdoaWNoIGlzIHRvIGJlIGV4cGVjdGVkLiAKCgpgYGB7ciwgaW5jbHVkZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kb2ZmZW5jZU1lbHQgPC0gbWVsdChkYXRhWzU6N10pCm9mZmVuY2VZYXJkYWdlIDwtIGdncGxvdChkYXRhPW9mZmVuY2VNZWx0LCBhZXMoeD12YWx1ZSwgY29sb3VyPXZhcmlhYmxlKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJZYXJkYWdlIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPZmZlbnNpdmUgWWFyZGFnZSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZT0iVHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90WWRfT2ZmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQYXNzWV9PZmYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c2hZX09mZiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJUb3RhbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQYXNzaW5nIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c2hpbmciKSkKCmRlZmVuc2VNZWx0IDwtIG1lbHQoZGF0YVsxMDoxMl0pCmRlZmVuc2VZYXJkYWdlIDwtIGdncGxvdChkYXRhPWRlZmVuc2VNZWx0LCBhZXMoeD12YWx1ZSwgY29sb3VyPXZhcmlhYmxlKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJZYXJkYWdlIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJEZWZlbnNlIFlhcmRhZ2UiKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWU9IlR5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdFlkX0RlZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFzc1lfRGVmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSdXNoWV9EZWYiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiVG90YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFzc2luZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSdXNoaW5nIikpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmZpcnN0RG93bnNPZmYgPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9WDFzdERfT2ZmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJGaXJzdCBEb3ducyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiRmlyc3QgRG93bnMgYnkgT2ZmZW5zZSIpCgpPZmZlbnNlVE8gPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9VE9fT2ZmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoKSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIlR1cm5vdmVycyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiVHVybm92ZXJzIGJ5IE9mZmVuc2UiKQoKZmlyc3REb3duc0RlZiA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1YMXN0RF9EZWYpKSArIAogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2RlbnNpdHkoKSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIkZpcnN0IERvd25zIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJGaXJzdCBEb3ducyBHaXZlbiBVcCBieSBEZWZlbnNlIikKCkRlZmVuc2VUTyA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1UT19EZWYpKSArIAogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcigpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiVHVybm92ZXJzIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJUdXJub3ZlcnMiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0Kb2ZmZW5jZVlhcmRhZ2UgLyAoZmlyc3REb3duc09mZiArIE9mZmVuc2VUTykKYGBgCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0KZGVmZW5zZVlhcmRhZ2UgLyAoZmlyc3REb3duc0RlZiArIERlZmVuc2VUTykKCmBgYAoKYGBge3IsIHJlc3VsdHM9RkFMU0V9CnlhcmRhZ2VDb3IgPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9VG90WWRfT2ZmLCB5PVRvdFlfRGVmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NCkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiT2ZmZW5zaXZlIFlhcmRzIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiRGVmZW5zaXZlIFlhcmRzIEdpdmVuIFVwIikKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPIHZzIEQgWWFyZGFnZSBDb3JyZWxhdGlvbiIpCgp0dXJub3ZlckNvciA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1UT19PZmYsIHk9VE9fRGVmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiT2ZmZW5zaXZlIFR1cm5vdmVycyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkRlZmVuc2l2ZSBUdXJub3ZlcnMiKQogICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIk8gdnMgRCBUdXJub3ZlciBDb3JyZWxhdGlvbiIpCiAgICAgICAgICAgICAgICAgICAgICAgIAp0b3RZdnNQYXNzQ29yIDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVBhc3NZX09mZiwgeT1Ub3RZZF9PZmYpKSArIAogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9LjUpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT01KSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJQYXNzIFlhcmRzIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiVG90YWwgWWFyZHMiKQogICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIk9mZmVuc2l2ZSBZYXJkYWdlIENvcnJlbGF0aW9uIikgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAKdG90WXZzUnVzaENvciA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1SdXNoWV9PZmYsIHk9VG90WWRfT2ZmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiUnVzaCBZYXJkcyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIlRvdGFsIFlhcmRzIikKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPZmZlbnNpdmUgWWFyZGFnZSBDb3JyZWxhdGlvbiIpIAogICAgICAgICAgICAgICAgICAgICAgICAKcGFzc1l2c1J1c2hDb3IgPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9UnVzaFlfT2ZmLCB5PVBhc3NZX09mZikpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0uNSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTUpKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIlJ1c2ggWWFyZHMiKSArIAogICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJQYXNzIFlhcmRzIikKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPZmZlbnNpdmUgWWFyZGFnZSBDb3JyZWxhdGlvbiIpCmBgYAoKQ29tcGFyaW5nIHRoZSBkZWZlbnNpdmUgcGxvdHMgdnMgdGhlIG9mZmVuc2l2ZSBwbG90cyBzaG93cyB0aGF0IHRoZSBkaXN0cmlidXRpb25zIGFyZSBleGFjdGx5IHRoZSBzYW1lIGJ1dCB0aGlzIGlzIHRvIGJlIGV4cGVjdGVkLiBTaW5jZSB0d28gdGVhbXMgcGxheSBpbiBhIGdhbWUsIHdlIGhhdmUgb2JzZXJ2YXRpb25zIGZvciBib3RoIHRlYW1zIGZyb20gdGhlIHNhbWUgZ2FtZS4gRm9yIGV4YW1wbGUsIHN1cHBvc2UgdGhlIEVhZ2xlcyBwbGF5IHRoZSBHaWFudHMgYW5kIGdhaW4gNDAwIHRvdGFsIHlhcmRzLiBUaGlzIHdpbGwgc2hvdyB1cCBhcyA0MDAgdW5kZXIgYFRvdFlkX09mZmAgYnV0IHdpbGwgc2hvdyB1cCBhZ2FpbiBpbiBhbm90aGVyIG9ic2VydmF0aW9uIG9mIHRoZSBHaWFudHMgYXMgYFRvdFlfRGVmYC4gV2Ugc2VlIGluIHRoZSB0d28gcGxvdHMgYmVsb3cgdGhhdCB0aGUgb2ZmZW5zaXZlIHN0YXRzIGRvIG5vdCBjb3JyZWxhdGUgd2l0aCB0aGUgZGVmZW5zaXZlIHN0YXRzIGZvciBlYWNoIG9ic2VydmF0aW9uLgoKYGBge3IsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA1fQp5YXJkYWdlQ29yICsgdHVybm92ZXJDb3IKYGBgCgpJdCBzaG91bGQgYmUgZXhwZWN0ZWQgdGhhdCBwYXNzaW5nIGFuZCBydXNoaW5nIHlhcmRzIGFyZSBjb3JyZWxhdGVkIHdpdGggdG90YWwgeWFyZHMgd2hpY2ggaXMgaW5kZWVkIHRoZSBjYXNlLiBTdXJwcmlzaW5nbHksIHRoZXJlIGlzIGxpdHRsZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHJ1c2ggYW5kIHBhc3MgeWFyZHMuCgpgYGB7ciwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDEwfQp0b3RZdnNQYXNzQ29yICsgdG90WXZzUnVzaENvciArIHBhc3NZdnNSdXNoQ29yCmBgYAoKVG8gZnVydGhlciBjYXB0dXJlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBvdXIgbnVtZXJpY2FsIHZhcmlhYmxlcyB3ZSBjcmVhdGUgYSBQZWFyc29uIGNvcnJlbGF0aW9uIHBsb3QuIFdlIHNlZSB0aGF0IG9mZmVuc2l2ZSBleHBlY3RlZCBwb2ludHMgZmVhdHVyZSBpcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHlhcmRhZ2UuIFRoZSBzYW1lIGFwcGxpZXMgZm9yIGRlZmVuc2l2ZSBleHBlY3RlZCBwb2ludHMgYW5kIHlhcmRhZ2UgZ2l2ZW4gdXAuIEFuZCBvZiBjb3Vyc2UgdGhlIHRvdGFsIHlhcmRhZ2UgaXMgZGVwZW5kZW50IG9uIHJ1c2hpbmcgYW5kIHBhc3NpbmcgeWFyZGFnZS4KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOSwgZmlnLndpZHRoID0gMTB9Cm51bWVyaWNEYXRhIDwtIGRhdGFbMzoxNl0KCmNvcnJlbGF0aW9uTWF0cml4IDwtIHJvdW5kKGNvcihudW1lcmljRGF0YSwgbWV0aG9kID0gInBlYXJzb24iKSwyKSAgCgpkaXN0IDwtIGFzLmRpc3QoKDEtY29ycmVsYXRpb25NYXRyaXgpLzIpCmhjIDwtIGhjbHVzdChkaXN0KQpjb3JyZWxhdGlvbk1hdHJpeCA8LWNvcnJlbGF0aW9uTWF0cml4W2hjJG9yZGVyLCBoYyRvcmRlcl0KCmNvcnJlbGF0aW9uTWF0cml4TWVsdCA8LSBtZWx0KGNvcnJlbGF0aW9uTWF0cml4KQoKZ2dwbG90KGRhdGEgPSBjb3JyZWxhdGlvbk1hdHJpeE1lbHQsIGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD12YWx1ZSkpICsgCiAgICAgICAgZ2VvbV90aWxlKCkgKyAKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0PTEpLAogICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICAgICAgICBnZW9tX3RleHQoYWVzKFZhcjIsIFZhcjEsIGxhYmVsID0gdmFsdWUpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0KSArIAogICAgICAgIGxhYnModGl0bGUgPSJQZWFyc29uIENvcnJlbGF0aW9uIEhlYXRtYXAiKSArCiAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudDIoKQoKYGBgCgojIyBSZWxhdGlvbnNoaXAgdG8gcmVzcG9uc2UgdmFyaWFibGVzCldlIHdvdWxkIG5vdyBsaWtlIHRvIHRha2UgYSBjbG9zZXIgbG9vayBhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gb3VyIGZlYXR1cmVzIGFuZCB0aGUgcmVzcG9uc2UgdmFyaWFibGVzLlRvIGNhcHR1cmUgdGhpcyByZWxhdGlvbnNoaXAsIHdlIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBmb3IgZWFjaCBudW1lcmljYWwgdmFyaWFibGUgYWdhaW5zdCBvdXIgcmVzcG9uc2UgdmFyaWFibGUuIEZvciBvdXIgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB3ZSBjcmVhdGUgZGVuc2l0eSBwbG90cy4KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTIsIGZpZy53aWR0aCA9IDEwfQpzY29yZU1lbHQgPSBtZWx0KGRhdGFbMzoxNl0saWQ9J1RtX3Njb3JlJykKCmdncGxvdChzY29yZU1lbHQsIGFlcyh4ID0gdmFsdWUsIHkgPSBUbV9zY29yZSkpICsgCiAgICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsKICAgICAgICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gMykKCmBgYAoKYGBge3IsIHJlc3VsdHM9RkFMU0V9CnNjb3JlVnRodXJzZGF5IDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9aXNUaHVyc2RheSkpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2RlbnNpdHkoKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIlBvaW50cyBTY29yZWQiKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiRGVuc2l0eSIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIlBvaW50cyBzY29yZWQgb24gVGh1cnNkYXkgR2FtZXMiKSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCnNjb3JlVnByaW1lIDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9aXNQcmltZVRpbWUpKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJQb2ludHMgU2NvcmVkIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkRlbnNpdHkiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJQb2ludHMgc2NvcmVkIG9uIFByaW1lIFRpbWUgR2FtZXMiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgCnNjb3JlVm90IDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9T1QpKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJQb2ludHMgU2NvcmVkIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkRlbnNpdHkiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJQb2ludHMgc2NvcmVkIGluIE92ZXJ0aW1lIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgIApzY29yZVZob21lIDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9YXRIb21lKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fZGVuc2l0eSgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiUG9pbnRzIFNjb3JlZCIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJEZW5zaXR5IikKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiUG9pbnRzIHNjb3JlZCBvbiBIb21lIHZzIEF3YXkgR2FtZXMiKQoKYGBgCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNn0KKHNjb3JlVnRodXJzZGF5ICsgc2NvcmVWcHJpbWUpIC8gKHNjb3JlVm90ICsgc2NvcmVWaG9tZSkKYGBgCgpPYnNlcnZhdGlvbnM6CgoxLiBEZWZlbnNpdmUgc3RhdGlzdGljcyBoYXZlIG5vIGJlYXJpbmcgb24gdGhlIHBvaW50cyBzY29yZWQgd2hpY2ggaXMgbm90IHRvbyBzdXJwcmlzaW5nIHNpbmNlIGRlZmVuc2VzIHJhcmVseSBzY29yZSBwb2ludHMuCjIuIFNwZWNpYWwgdGVhbXMgZXhwZWN0ZWQgcG9pbnRzIGhhcyBubyBjb3JyZWxhdGlvbiB3aXRoIHBvaW50cyBzY29yZWQuIFRoaXMgaXMgYSBiaXQgc3VycHJpc2luZyBzaW5jZSwgZmllbGQgZ29hbHMgYW5kIGV4dHJhIHBvaW50cyBhcmUgYSBzaWduaWZpY2FudCBjaHVuayBvZiBwb2ludHMgc2NvcmVkIGR1cmluZyBhIG5vcm1hbCBnYW1lLgozLiBUdXJub3ZlcnMgbWF5IGhhdmUgYSBzbGlnaHQgY29ycmVsYXRpb24uCjQuIEEgZGlmZmVyZW5jZSBpbiB0aGUgZGlzdHJpYnV0aW9uIGJldHdlZW4gZ2FtZXMgdGhhdCB3ZW50IGludG8gb3ZlcnRpbWUgdnMgdGhvc2UgdGhhdCBkaWQgbm90LiBTaW1pbGFybHksIGhvbWUgdnMgYXdheSBnYW1lcyBoYXZlIGEgc2xpZ2h0IGRpZmZlcmVuY2UgaW4gZGlzdHJpYnV0aW9ucy4gCgpQbG90dGluZyBvdXIgZmVhdHVyZXMgYWdhaW5zdCBvdXIgc2Vjb25kIHJlc3BvbnNlIHZhcmlhYmxlLCB3ZSBzZWUgdGhhdCBhbG1vc3QgYWxsIGZlYXR1cmVzIGhhdmUgYSBkaWZmZXJlbmNlIGluIHRoZXJlIGRpc3RyaWJ0aW9ucyBmb3IgYSB3aW4gdnMgYSBsb3NzLiBUaGUgdHdvIHR1cm5vdmVyIGZlYXR1cmVzIGxvb2sgYSBiaXQgb2RkIGFuZCB0aGV5IG1heSBwb3NlIHByb2JsZW1zIGRvd25zdHJlYW0uCgpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDEwfQp3aW5NZWx0ID0gbWVsdChkYXRhW2MoMzoxMywxOSldLGlkPSd3aW4nKQoKZ2dwbG90KHdpbk1lbHQsIGFlcyh4PXZhbHVlLCBjb2xvdXI9d2luKSkgKyAKICAgICAgICBnZW9tX2RlbnNpdHkoKSArIAogICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZSIpCgpgYGAKCgojIExpbmVhciBSZWdyZXNzaW9uClBvaW50cyBhcmUgcHJpbWFyaWx5IHNjb3JlZCBieSB0aGUgb2ZmZW5zZSBhbmQgYSBzbWFsbCBhbW91bnQgYnkgdGhlIHNwZWNpYWwgdGVhbXMgdmlhIGV4dHJhIHBvaW50cywgZmllbGQgZ29hbHMsIHB1bnQgYW5kIGtpY2sgcmV0dXJucy4gSW4gcmFyZSBjYXNlcywgcG9pbnRzIGNhbiBiZSBzY29yZWQgYnkgdGhlIGRlZmVuc2UuIEZvciB0aGlzIHRvIGhhcHBlbiwgYSB0dXJub3ZlciBpcyByZXF1aXJlZC4gVGhpcyBmYWN0IGhlbHBzIHVzIGNob29zZSAkfC4zfCQgYXMgdGhlIGN1dG9mZiBmb3Igc2VsZWN0aW5nIGZlYXR1cmVzIGZyb20gdGhlIGNvcnJlbGF0aW9uIHBsb3QuIFRoaXMgZGVjaXNpb24gaXMgYWxzbyBzdXBwb3J0ZWQgYnkgb3VyIHNjYXR0ZXIgcGxvdHMuCgojIyBNb2RlbCBPbmUKVGhlIGZpcnN0IG1vZGVsIHdlIGJ1aWxkIGlzIGEgbmFpdmUgbW9kZWwgdG8gc2V0IGEgYmFzZWxpbmUuIEZyb20gb3VyIHZpc3VhbGl6YXRpb24sIHdlIGtub3cgdGhhdCBvZmZlbnNpdmUgZXhwZWN0ZWQgcG9pbnRzIHdhcyB0aGUgaGlnaGVzdCBjb3JyZWxhdGVkIGZlYXR1cmUgdG8gb3VyIHJlc3BvbnNlIHZhcmlhYmxlIHNvIHdlIGNob29zZSB0aGlzIGluc3RlYWQgb2Ygb3RoZXIgb2ZmZW5zaXZlcyBzdGF0cy4gTGV0ICRPPSRgT1RgLCRIJD1gYXRIb21lYCwgJFAkPWBUbV9zY29yZWAJLCAkRl9PJD1gMXN0RF9PZmZgLCAkWV9PJCA9IGBUb3RZZF9PZmZgLCAkUF9PJCA9IGBQYXNzWV9PZmZgLCAkUl9PJCA9YFJ1c2hZX09mZmAsICRUT19PJCA9YFRPX09mZmAsICRGX0QkID1gMXN0RF9EZWZgLCAkVF9EJCA9YFRvdFlfRGVmYCwgJFBfRCQgPWBQYXNzWV9EZWZgLCAkUl9EJCA9IGBSdXNoWV9EZWZgLCAkVE9fRCQgPWBUT19EZWZgLCAkRV9PJCA9YE9mZmVuc2VFeHBgLCAkRV9EJCA9IGBEZWZlbnNlRXhwYCwgJEVfUyRgU3BUbXNfRXhwYCwgJE4kID0gYGlzUHJpbWVUaW1lYCwgYW5kICRUJCA9IGBpc1RodXJzZGF5YC4KCk91ciBmaXJzdCBtb2RlbDoKJCRNMTogXHRleHR7UG9pbnRzfSA9IFxhbHBoYV8wICsgXGFscGhhXzFFX0QrIFxhbHBoYV8yRV9PICsgXGFscGhhXzNFX1MgKyBcYWxwaGFfNEZfTyArIFxhbHBoYV81IEggKyBcYWxwaGFfNiBUT19PICsgXGFscGhhXzcgVE9fRCArIFxhbHBoYV84IE8gKyBcYWxwaGFfOSBUICsgXGFscGhhX3sxMH0gTiArIFxlcHNpbG9uJCQKCgpgYGB7ciwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDV9Cm5haXZlTW9kZWwgPSBsbShUbV9zY29yZSB+IFNwVG1zX0V4cCArIE9mZmVuc2VFeHAgKyBEZWZlbnNlRXhwICsgWDFzdERfT2ZmICsgVE9fT2ZmICsgVE9fRGVmICsgYXRIb21lICsgT1QgKyBpc1RodXJzZGF5ICsgaXNQcmltZVRpbWUsIGRhdGEgPSBkYXRhKQpwYXIobWZyb3c9YygyLDIpLCBtYXI9YygyLDMsMiwyKSkKcGxvdChuYWl2ZU1vZGVsKQpgYGAKCmBgYHtyfQprYWJsZShzdW1tYXJ5KG5haXZlTW9kZWwpJGNvZWYsIAogICAgICBjYXB0aW9uID0gIlN1bW1hcml6ZWQgc3RhdGlzdGljcyBvZiB0aGUgcmVncmVzc2lvbiBjb2VmZmljaWVudHMiKQpgYGAKCkZyb20gdGhlIG91dHB1dCBvZiBvdXIgZmlyc3QgbW9kZWwsIHdlIHNlZSB0aGF0IHBsYXlpbmcgYXQgaG9tZSBoYWQgYSBzbWFsbCBlZmZlY3Qgb24gdGhlIG91dGNvbWUuIEZ1cnRoZXJtb3JlLCB3ZSBrbm93IGZyb20gb3VyIGNvcnJlbGF0aW9uIHBsb3RzLCB0aGF0IHRoZSBkZWZlbnNpdmUgYW5kIHNwZWNpYWwgdGVhbXMgaGFkIGxpdHRsZSByZWxhdGlvbnNoaXAgdG8gb3VyIHJlc3BvbnNlIHZhcmlhYmxlLiBPdXIgc2Vjb25kIG1vZGVsIGlzIGZvY3VzZWQgb24gb2ZmZW5zaXZlIHN0YXRzIGFuZCB3ZSByZW1vdmUgdGhlIGBhdEhPTUVgIHZhcmlhYmxlLgoKIyMgTW9kZWwgMgpPdXIgc2Vjb25kIG1vZGVsOgokJE0yOiBcdGV4dHtQb2ludHN9ID0gXGFscGhhXzAgKyBcYWxwaGFfMUVfTyArICBcYWxwaGFfMkZfTyArIFxhbHBoYV8zIFRPX0QgKyBcYWxwaGFfNCBUT19PICsgXGFscGhhXzUgTyArIFxhbHBoYV82IFQgKyBcYWxwaGFfNyBOICsgXGVwc2lsb24kJAoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA1fQpvZmZNb2RlbCA9IGxtKFRtX3Njb3JlIH4gT2ZmZW5zZUV4cCArIFgxc3REX09mZiArIFRPX09mZiArIFRPX0RlZiArIGlzVGh1cnNkYXkgKyBPVCArIGlzUHJpbWVUaW1lLCBkYXRhID0gZGF0YSkgICAKcGFyKG1mcm93PWMoMiwyKSwgbWFyPWMoMiwzLDIsMikpCnBsb3Qob2ZmTW9kZWwpCmBgYAoKYGBge3J9CmthYmxlKHN1bW1hcnkob2ZmTW9kZWwpJGNvZWYsIAogICAgICBjYXB0aW9uID0gIlN1bW1hcml6ZWQgc3RhdGlzdGljcyBvZiB0aGUgcmVncmVzc2lvbiBjb2VmZmljaWVudHMiKQpgYGAKCiMjIE1vZGVsIFRocmVlClRoZSBuZXh0IHR3byBtb2RlbHMgd2UgYnVpbGQsIHdlIHJlcGxhY2Ugb2ZmZW5zaXZlIGV4cGVjdGVkIHBvaW50cyBieSB0aGUgdGhyZWUgeWFyZGFnZSBzdGF0aXN0aWNzLiBUaGUgdGhpcmQgbW9kZWwgdXNlcyBgVG90WWRfT2ZmYCBhbmQgZm91cnRoIG1vZGVsIHdpbGwgdXNlIGBSdXNoWV9PZmZgICsgYFBhc3NZX09mZmAuCgokJE0zOiBcdGV4dHtQb2ludHN9ID0gXGFscGhhXzAgKyBcYWxwaGFfMVlfTyArICBcYWxwaGFfMkZfTyArIFxhbHBoYV8zIFRPX0QgKyBcYWxwaGFfNCBUT19PICsgXGFscGhhXzUgTyArIFxhbHBoYV82IFQgKyBcYWxwaGFfNyBOICsgXGFscGhhXzggSCArIFxlcHNpbG9uJCQKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNX0KeWFyZE1vZGVsID0gbG0oVG1fc2NvcmUgfiBUb3RZZF9PZmYgKyBYMXN0RF9PZmYgKyBUT19PZmYgKyBUT19EZWYgKyBhdEhvbWUgKyBpc1RodXJzZGF5ICsgT1QgKyBpc1ByaW1lVGltZSwgZGF0YSA9IGRhdGEpICAgCnBhcihtZnJvdz1jKDIsMiksIG1hcj1jKDIsMywyLDIpKQpwbG90KHlhcmRNb2RlbCkKYGBgCgojIyBNb2RlbCBGb3VyCkluIG91ciBmb3VydGggbW9kZWwsIHdlIHVzZSBib3RoIHJ1c2ggYW5kIHBhc3NpbmcgeWFyZHMgaW5zdGVhZCBvZiB0b3RhbCB5YXJkcy4KJCRNNDogXHRleHR7UG9pbnRzfSA9IFxhbHBoYV8wICsgXGFscGhhXzFSX08gKyBcYWxwaGFfMVBfTyArIFxhbHBoYV8zRl9PICsgXGFscGhhXzQgVE9fRCArIFxhbHBoYV81IFRPX08gKyBcYWxwaGFfNiBPICsgXGFscGhhXzcgVCArIFxhbHBoYV84IE4gKyBcYWxwaGFfOSBIICsgXGVwc2lsb24kJAoKYGBge3IsZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDV9CnRlc3QgPSBkYXRhWy1jKDQzOSw0NzkpLF0KdHlwZVlhcmRhZ2VfbW9kZWwgPSBsbShUbV9zY29yZSB+IFgxc3REX09mZiArIFJ1c2hZX09mZiArIFBhc3NZX09mZiArIFRPX09mZiArIFRPX0RlZiArIGF0SG9tZSArIGlzVGh1cnNkYXkgKyBpc1ByaW1lVGltZSArIE9ULCBkYXRhKSAgIApwYXIobWZyb3c9YygyLDIpLCBtYXI9YygyLDMsMiwyKSkKcGxvdCh0eXBlWWFyZGFnZV9tb2RlbCkKYGBgCgpgYGB7ciwgcmVzdWx0cz1GQUxTRX0Kc3VtbWFyeShuYWl2ZU1vZGVsKSRyLnNxdWFyZWQKc3VtbWFyeShvZmZNb2RlbCkkci5zcXVhcmVkCnN1bW1hcnkoeWFyZE1vZGVsKSRyLnNxdWFyZWQKc3VtbWFyeSh0eXBlWWFyZGFnZV9tb2RlbCkkci5zcXVhcmVkCmBgYApUaGUgcmVzcGVjdGl2ZSAkUl4yJCB2YWx1ZXMgZm9yIG91ciBmb3VyIG1vZGVscyBhcmU6IAoKMS4gbmFpdmVNb2RlbCA9IDAuNzcyNjg4LAoyLiBvZmZNb2RlbCA9IDAuNzMwOTg2NCwKMy4geWFyZE1vZGVsID0gMC42MTgxNTMzLAo0LiB0eXBlWWFyZGFnZV9tb2RlbCA9IDAuNjE4MzMyMgoKT3VyIG1vZGVscyBiYXNlZCBvbiBleHBlY3RlZCB2YWx1ZSBmZWF0dXJlcyBwZXJmb3JtIG11Y2ggYmV0dGVyIHRoYW4gdGhlIG9uZXMgdXNpbmcgeWFyZGFnZS4gVGhpcyBtYXkgYmUgYmVjYXVzZSB0aGUgZXhwZWN0ZWQgdmFsdWUgZmVhdHVyZXMgYXJlIGJhc2VkIG9uIG90aGVyIGluZm9ybWF0aW9uIGFuZCB0aHVzIGFyZSBtb3JlIGluZm9ybWF0aXZlLiAKCmBgYHtyfQojbGlicmFyeShNQVNTKQojYmMgPSBib3hjb3goVG1fc2NvcmUgKyAxIH4gWDFzdERfT2ZmICsgUnVzaFlfT2ZmICsgUGFzc1lfT2ZmICsgVE9fT2ZmICsgVE9fRGVmICsgYXRIb21lICsgaXNUaHVyc2RheSArIGlzUHJpbWVUaW1lLCAKIyAgICAgICBkYXRhID0gZGF0YSwgCiMgICAgICAgbGFtYmRhID0gc2VxKC0yLCAyLCBsZW5ndGggPSAyMCksIAojICAgICAgIHhsYWI9ZXhwcmVzc2lvbihwYXN0ZShsYW1iZGEpKSkKCiN0aXRsZShtYWluID0gIkJveC1Db3ggVHJhbnNmb3JtYXRpb246IDk1JSBDSSBvZiBsYW1iZGEiLCBjb2wubWFpbiA9ICJuYXZ5IiwgY2V4Lm1haW4gPSAwLjkpCgpgYGAKCiMgTG9naXN0aWMgcmVncmVzc2lvbgoKRm9yIG91ciBsb2dpc3RpYyBtb2RlbHMsIHdlIHdpbGwgb21pdCB0aGUgdGhyZWUgZXhwZWN0ZWQgcG9pbnRzIGZlYXR1cmVzIGJlY2F1c2UgdGhleSBjYXB0dXJlIHRoZSBtYXJnaW4gb2YgcG9pbnRzIGJldHdlZW4gdHdvIHRlYW1zLiBUaGUgZmlyc3QgbW9kZWwgd2UgYnVpbGQgaW5jbHVkZXMgYWxsIGZlYXR1cmVzIGFzaWRlIGZyb20gZXhwZWN0ZWQgcG9pbnRzIHNpbmNlIG91ciBleHBsb3JhdGlvbiBzaG93ZWQgYSBkaWZmZXJlbmNlIGluIGRpc3RyaWJ1dGlvbiBmb3IgZWFjaCBmZWF0dXJlLgoKIyMgTW9kZWwgT25lCkluIG91ciBmb3VydGggbW9kZWwsIHdlIHVzZSBib3RoIHJ1c2ggYW5kIHBhc3NpbmcgeWFyZHMgaW5zdGVhZCBvZiB0b3RhbCB5YXJkcy4KJCRNMTogXHRleHR7d2lufSA9IFxhbHBoYV8wICsgXGFscGhhXzFQICsgXGFscGhhXzNGX08gKyBcYWxwaGFfNCBGX0QgKyAgXGFscGhhXzUgVE9fRCArIFxhbHBoYV82IFRPX08gKyBcYWxwaGFfNyBZX08gKyBcYWxwaGFfOCBZX0QgKyBcYWxwaGFfOSBPICsgXGFscGhhX3sxMH0gVCArIFxhbHBoYV97MTF9IE4gKyBcYWxwaGFfezEyfSBIICsgXGVwc2lsb24kJAoKYGBge3J9CmRhdGEkd2luIDwtIGFzLmZhY3RvcihkYXRhJHdpbikKbG9nTW9kZWwxID0gZ2xtKHdpbiB+IFRtX3Njb3JlICsgWDFzdERfT2ZmICsgVG90WWRfT2ZmICsgVE9fT2ZmICsgWDFzdERfRGVmICsgVG90WV9EZWYgKyAgVE9fRGVmICsgYXRIb21lICsgaXNUaHVyc2RheSArIGlzUHJpbWVUaW1lICsgT1QsIGRhdGEgPSBkYXRhLCBmYW1pbHkgPSBiaW5vbWlhbCkKCm1vZGVsMV9zaWduaWZpY2FudCA9IHN1bW1hcnkobG9nTW9kZWwxKSRjb2VmCmthYmxlKG1vZGVsMV9zaWduaWZpY2FudCwgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIHRoZSBzaWduaWZpY2FudCB0ZXN0cyBvZiAKICAgICAgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwiKQpgYGAKCkZyb20gdGhlIGFib3ZlIG91dHB1dCwgd2UgY2FuIHNlZSB0aGF0IG91ciBiaW5hcnkgdmFyaWFibGVzIGFuZCBmaXJzdCBkb3ducyBnaXZlbiB1cCBieSB0aGUgZGVmZW5zZSBoYXZlIGxpdHRsZSBpbXBhY3QgYW5kIGFyZSBub3Qgc2lnbmlmaWNhbnQuIFNvIGluIG91ciBzZWNvbmQgbW9kZWwsIHdlIHJlbW92ZSB0aGVtLgoKIyMgTW9kZWwgVHdvCgokJE0xOiBcdGV4dHt3aW59ID0gXGFscGhhXzAgKyBcYWxwaGFfMVAgKyBcYWxwaGFfMkZfTyArICBcYWxwaGFfMyBUT19EICsgXGFscGhhXzQgVE9fTyArIFxhbHBoYV81IFlfTyArIFxhbHBoYV82IFlfRCArIFxlcHNpbG9uJCQKCmBgYHtyfQpsb2dNb2RlbDIgPSBnbG0od2luIH4gVG1fc2NvcmUgKyBYMXN0RF9PZmYgKyBUb3RZZF9PZmYgKyBUT19PZmYgKyBUb3RZX0RlZiArICBUT19EZWYsIGRhdGEgPSBkYXRhLCBmYW1pbHkgPSBiaW5vbWlhbCkKCm1vZGVsMl9zaWduaWZpY2FudCA9IHN1bW1hcnkobG9nTW9kZWwyKSRjb2VmCmthYmxlKG1vZGVsMl9zaWduaWZpY2FudCwgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIHRoZSBzaWduaWZpY2FudCB0ZXN0cyBvZiAKICAgICAgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwiKQpgYGAKCiMgUHJlZGljdGl2ZSBNb2RlbGluZyAKCiMjIExpbmVhciBSZWdyZXNzaW9uIApXZSBwaWNrIG91ciBmaXJzdCBhbmQgdGhpcmQgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzIHRvIHBlcmZvcm0gcHJlZGljdGl2ZSBtb2RlbGluZy4gRmlyc3Qgd2Ugc3BsaXQgb3VyIGRhdGEgJDgwOjIwJCBiZXR3ZWVuIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMuIEZyb20gdGhlcmUsIHdlIHBlcmZvcm0gNS1mb2xkIGNyb3NzIHZhbGlkYXRpb24gb24gb3VyIHRyYWluaW5nIHNldCBhbmQgdGhlbiB1c2Ugb3VyIHRlc3Qgc2V0IHRvIGdldCBmaW5hbCByZXN1bHRzIGZvciBvdXIgY2hvc2VuIG1vZGVsLgpgYGB7cn0KdHJhaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGRhdGEkVG1fc2NvcmUsIHA9IDAuOCwgbGlzdCA9IEZBTFNFKQp0cmFpbiA8LSBkYXRhW3RyYWluSW5kZXgsXQp0ZXN0IDwtIGRhdGFbLXRyYWluSW5kZXgsXQpgYGAKCgpgYGB7cn0KdHJhaW4uNWZvbGQgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDUpCgptb2RlbE5haXZlLjVmb2xkIDwtIHRyYWluKFRtX3Njb3JlIH4gU3BUbXNfRXhwICsgT2ZmZW5zZUV4cCArIERlZmVuc2VFeHAgKyBYMXN0RF9PZmYgKyBUT19PZmYgKyBUT19EZWYgKyBhdEhvbWUgKyBPVCArIGlzVGh1cnNkYXkgKyBpc1ByaW1lVGltZSwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi41Zm9sZCkKCiNwcmludChtb2RlbE5haXZlLjVmb2xkKQprYWJsZShtb2RlbE5haXZlLjVmb2xkJHJlc3VsdHMsIGNhcHRpb24gPSAiTW9kZWwgMSAtIE5haXZlIikKYGBgCgpgYGB7cn0KdHJhaW4uNWZvbGQgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDUpCgptb2RlbFlhcmQuNWZvbGQgPC0gdHJhaW4oVG1fc2NvcmUgfiBUb3RZZF9PZmYgKyBYMXN0RF9PZmYgKyBUT19PZmYgKyBUT19EZWYgKyBhdEhvbWUgKyBpc1RodXJzZGF5ICsgT1QgKyBpc1ByaW1lVGltZSwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi41Zm9sZCkKCiNwcmludChtb2RlbFlhcmQuNWZvbGQpCmthYmxlKG1vZGVsWWFyZC41Zm9sZCRyZXN1bHRzLGNhcHRpb24gPSAiTW9kZWwgMiAtIFRvdGFsIFlhcmRzIikKYGBgCgpXZSBzZWUgdGhhdCBtb2RlbCAxIHBlcmZvcm1zIGJldHRlciBhY3Jvc3MgYWxsIG1ldHJpY3MgYW5kIHRoZXJlZm9yZSBjaG9zZSBpdCB0byBiZSBvdXIgZmluYWwgbW9kZWwuIFRoZSBmaW5hbCByZXN1bHRzIGFyZToKCmBgYHtyfQpsbUZpbmFsID0gbG0oVG1fc2NvcmUgfiBTcFRtc19FeHAgKyBPZmZlbnNlRXhwICsgRGVmZW5zZUV4cCArIFgxc3REX09mZiArIFRPX09mZiArIFRPX0RlZiArIGF0SG9tZSArIE9UICsgaXNUaHVyc2RheSArIGlzUHJpbWVUaW1lLCBkYXRhID0gdHJhaW4pCmxtRmluYWxQcmVkaWN0ID0gcHJlZGljdChsbUZpbmFsLCBuZXdkYXRhID0gdGVzdCkKbG1GaW5hbE1lYW4gPSBtZWFuKChsbUZpbmFsUHJlZGljdCAtIHRlc3QkVG1fc2NvcmUpXjIpCgpkYXRhLmZyYW1lKFJNU0UgPSBSTVNFKGxtRmluYWxQcmVkaWN0LCB0ZXN0JFRtX3Njb3JlKSwKICAgICAgICAgICBSMiA9IFIyKGxtRmluYWxQcmVkaWN0LCB0ZXN0JFRtX3Njb3JlKSwKICAgICAgICAgICBNQUUgPSBNQUUobG1GaW5hbFByZWRpY3QsIHRlc3QkVG1fc2NvcmUpKQpgYGAKCiMjIExvZ2lzdGljIFJlZ3Jlc3Npb24gQ3Jvc3MgVmFsaWRhdGlvbgpXZSB1c2Ugb3VyIHRyYWluaW5nIGRhdGEgdG8gcGVyZm9ybSA1LWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiBhbmQgdGhlbiB1c2Ugb3VyIHRlc3Qgc2V0IHRvIGdldCBmaW5hbCByZXN1bHRzIGZvciBvdXIgY2hvc2VuIG1vZGVsLgoKYGBge3J9CnRyYWluLjVmb2xkIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSA1KQoKbW9kZWxMb2dBbGwuNWZvbGQgPC0gdHJhaW4od2luIH4gVG1fc2NvcmUgKyBYMXN0RF9PZmYgKyBUb3RZZF9PZmYgKyBUT19PZmYgKyBYMXN0RF9EZWYgKyBUb3RZX0RlZiArICBUT19EZWYgKyBhdEhvbWUgKyBpc1RodXJzZGF5ICsgaXNQcmltZVRpbWUgKyBPVCwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiZ2xtIiwKICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PWJpbm9taWFsLAogICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi41Zm9sZCkKCiNwcmludChtb2RlbExvZ0FsbC41Zm9sZCkKa2FibGUobW9kZWxMb2dBbGwuNWZvbGQkcmVzdWx0cywgY2FwdGlvbj0iTW9kZWwgMSAtIEFsbCBGZWF0dXJlcyIpCmBgYAoKYGBge3J9CnRyYWluLjVmb2xkIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSA1KQoKbW9kZWxMb2cyLjVmb2xkIDwtIHRyYWluKHdpbiB+IFRtX3Njb3JlICsgWDFzdERfT2ZmICsgVG90WWRfT2ZmICsgVE9fT2ZmICsgVG90WV9EZWYgKyAgVE9fRGVmLAogICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW4sCiAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG0iLAogICAgICAgICAgICAgICAgICAgICBmYW1pbHk9Ymlub21pYWwsCiAgICAgICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluLjVmb2xkKQoKI3ByaW50KG1vZGVsTG9nMi41Zm9sZCkKa2FibGUobW9kZWxMb2cyLjVmb2xkJHJlc3VsdHMsIGNhcHRpb249Ik1vZGVsIDIgLSBTb21lIEZlYXR1cmVzIikKYGBgCgpDb2hlbidzIGthcHBhIGFuZCBhY2N1cmFjeSBhcmUgaGlnaCBpbiBib3RoIG1vZGVscy4gV2Ugc2VlIGxpdHRsZSBkcm9wIG9mZiBpbiB0aGUgc2Vjb25kLCBzaW1wbGVyIG1vZGVsIGFuZCB0aHVzIGNob29zZSBpdCBhcyBvdXIgZmluYWwgbW9kZWwuIFdlIG5vdyB1c2Ugb3VyIGVudGlyZSB0cmFpbmluZyBkYXRhIHRvIGZpdCB0aGUgbW9kZWwgYW5kIHRlc3QgaXQgb24gb3VyIHRlc3QgZGF0YS4gIEEgY3VmdXNpb24gbWF0cml4IGlzIHByb3ZpZGVkIGZvciB0aGUgZmluYWwgbW9kZWwsIGFsb25nIHdpdGggdmFyaW91cyBzdGF0aXN0aWNzIHRvIG1lYXN1cmUgbW9kZWwgcGVyZm9ybWFuY2UsIHdpdGggYWNjdXJhY3kgYXQgJDkwJCUuICAKCmBgYHtyfQojZ2xtRmluYWwgPSBnbG0od2luIH4gVG1fc2NvcmUgKyBYMXN0RF9PZmYgKyBUb3RZZF9PZmYgKyBUT19PZmYgKyBUb3RZX0RlZiArICBUT19EZWYsIGRhdGEgPSB0cmFpbiwgZmFtaWx5ID0gYmlub21pYWwpCgpnbG1GaW5hbCA8LSB0cmFpbih3aW4gfiBUbV9zY29yZSArIFgxc3REX09mZiArIFRvdFlkX09mZiArIFRPX09mZiArIFRvdFlfRGVmICsgIFRPX0RlZiwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiZ2xtIiwKICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PWJpbm9taWFsLCkKCmdsbUZpbmFsUHJlZGljdCA9IHByZWRpY3QoZ2xtRmluYWwsIHRlc3QpCgpjb25mdXNpb25NYXRyaXgoZGF0YT1nbG1GaW5hbFByZWRpY3QsIHRlc3Qkd2luKQpgYGAKCiMgQ29uY2x1c2lvbgpPdXIgbW9kZWxzIHdvcmtlZCBmYWlybHkgd2VsbCBvbiBhIGxpbWl0ZWQgZGF0YSBzZXQgYnV0IGNvdWxkIHVzZSBpbXByb3ZlbWVudC4gTW9yZSBkYXRhIG5ldmVyIGh1cnRzLiBQZXJoYXBzIG91ciBtb2RlbHMsIHBhcnRpY3VsYXJseSBvdXIgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwsIHdvdWxkIHBlcmZvcm0gYmV0dGVyIGlmIHdlIGhhZCBkYXRhIGFjcm9zcyBtdWx0aXBsZSB5ZWFycyBvciBpZiB3ZSBoYWQgbW9yZSBmZWF0dXJlcyBsaWtlIHRpbWUgb2YgcG9zc2Vzc2lvbiwgbG9zcyBvZiBkb3ducywgM3JkIGFuZCA0dGggZG93biBjb252ZXJzaW9ucywgZXRjLiAKCk9uZSB0aGluZyBub3QgbWVudGlvbmVkIGluIHRoZSBhYm92ZSBzZWN0aW9ucyBpcyB0aGUgQm94LUNveCB0cmFuc2Zvcm1hdGlvbi4gVGhpcyB3YXMgYXR0ZW1wdGVkIGZvciB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gYnV0IGhhZCBsaXR0bGUgZWZmZWN0IG9uIHBlcmZvcm1hbmNlIGFuZCBvY2Nhc2lvbmFsbHkgaHVydCB0aGUgcGVyZm9ybWFuY2UuIFRoZXJlZm9yZSwgaXQgd2FzIGxlZnQgb3V0LgoKRnVydGhlcm1vcmUsIHRoZSBleHBlY3RlZCBwb2ludHMgZmVhdHVyZXMgd2VyZSB0aGUgYmVzdCBwZXJmb3JtZXJzIGZvciBsaW5lYXIgcmVncmVzc2lvbiB3aGljaCBpcyBsZXNzIHRoYW4gaWRlYWwgc2luY2UgdGhleSBhcmUgb3BhcXVlIHZhcmlhYmxlcy4gSXQgaXMgbm90IGNsZWFyIGhvdyB0aGV5IGFyZSBjYWxjdWxhdGVkIGZyb20gb3RoZXIgc3RhdGlzdGljcyBieSBwcm8tZm9vdGJhbGwtcmVmZXJlbmNlIGFuZCBpdCB3b3VsZCBiZSBiZXR0ZXIgdG8gaGF2ZSB0aGUgYWN0dWFsIHN0YXRpc3RpY3MgaW5zdGVhZC4K